package com.putao.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.putao.base.BaseService;
import com.putao.base.BaseWrapper;
import com.putao.constants.ColorList;
import com.putao.constants.Constants;
import com.putao.domain.AccountBook;
import com.putao.domain.Category;
import com.putao.error.BusinessException;
import com.putao.mapper.AccountBookMapper;
import com.putao.service.AccountBookService;
import com.putao.service.CategoryService;
import com.putao.utils.*;
import com.putao.vo.AccountBookVo;
import com.putao.vo.BaseVo;
import com.putao.vo.CategoryVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.putao.enums.SystemCodeEnum.ACCOUNT_BOOK_NAME_FORMAT_ERROR;
import static com.putao.enums.SystemCodeEnum.ACCOUNT_BOOK_NUMBER_OVER;

/**
 * @author fuhehuang
 * @email 2628279194@qq.com
 */
@Service
public class AccountBookServiceImpl extends ServiceImpl<AccountBookMapper, AccountBook> implements AccountBookService, BaseService<AccountBook> {

    @Autowired
    private SnowflakeConfig snowflakeConfig;
    @Autowired
    private CategoryService categoryService;

    @Override
    public AccountBook saveAccountBook(AccountBookVo accountBookVO) {
        AccountBook accountBook = new AccountBook();
        BeanUtils.copyProperties(accountBookVO, accountBook);
        String userId = ThreadLocalUtil.getUserId();
        this.check(accountBook, null);
        // 账本个数不能超过5个
        QueryWrapper<AccountBook> wrapper = new BaseWrapper<AccountBook>().init(userId);
        List<AccountBook> accountBookList = this.list(wrapper);
        if (CollectionUtil.isNotEmpty(accountBookList) && accountBookList.size() >= 5) {
            throw new BusinessException(ACCOUNT_BOOK_NUMBER_OVER.getErrorMsg());
        }
        accountBook.insertInit(snowflakeConfig.snowflakeId());
        accountBook.setWidth(StringUtils.calculateLength(accountBook.getName()));
        ColorList.setColor(accountBook, accountBook.getColorIndex());
        accountBook.setUsername(ThreadLocalUtil.getUserName());
        this.save(accountBook);
        return accountBook;
    }

    /**
     * 检查图标，名称，颜色，预算不能为空，图标，名称不能重复
     * @param accountBook 账本
     * @param id 账本id
     */
    private void check(AccountBook accountBook, String id) {
        AssertUtil.hasText(accountBook.getName(), "名称不能为空");
        AssertUtil.hasText(accountBook.getIcon(), "图标不能为空");
        AssertUtil.hasText(accountBook.getColorIndex() + "", "颜色不能为空");
        AssertUtil.hasText(accountBook.getBudget() + "", "预算不能为空");
        // 名称不能超过5个字符
        if (accountBook.getName().length() >= 7) {
            throw new BusinessException(ACCOUNT_BOOK_NAME_FORMAT_ERROR.getErrorMsg());
        }
        // 检查名称，图标不能重复
        this.checkIsEmptyAndRepeat(id, new QueryWrapper<>(), accountBook, "name", "名称重复了", "名称不能为空");
        this.checkIsEmptyAndRepeat(id, new QueryWrapper<>(), accountBook, "icon", "图标重复了", "图标不能为空");
    }

    /**
     * 移动端查询指定用户的所有账本，和账本对应的分类
     * @param baseVo
     * @param userId
     * @param wrapper
     * @return
     */
    @Override
    public List<AccountBookVo> selectListByPhone(BaseVo baseVo, String userId, QueryWrapper<AccountBook> wrapper) {
        wrapper.orderByDesc("create_time");
        List<AccountBook> accountBookList = this.list(wrapper);
        if (CollectionUtil.isEmpty(accountBookList)) {
            return new ArrayList<>();
        }
        accountBookList.get(0).setSelected(true);
        List<AccountBookVo> accountBookVoList = accountBookList.stream().map(accountBook -> {
            AccountBookVo accountBookVO = new AccountBookVo();
            BeanUtils.copyProperties(accountBook, accountBookVO);
            return accountBookVO;
        }).collect(Collectors.toList());
        List<CategoryVo> categoryVoList = categoryService.selectListByPhone(baseVo, userId, new BaseWrapper<Category>().init(userId));
        if (CollectionUtil.isNotEmpty(categoryVoList)) {
            Map<String, List<CategoryVo>> accountBookIdCategoryMap = categoryVoList.stream().collect(Collectors.groupingBy(Category::getAccountBookId));
            for (AccountBookVo accountBookVO : accountBookVoList) {
                List<CategoryVo> categoryVos = accountBookIdCategoryMap.get(accountBookVO.getId());
                if (CollectionUtil.isNotEmpty(categoryVos)) {
                    Map<String, List<CategoryVo>> categoryTypeMap = categoryVos.stream().collect(Collectors.groupingBy(Category::getType));
                    List<CategoryVo> payCategoryList = categoryTypeMap.get(Constants.CATEGORY_TYPE_PAY);
                    accountBookVO.setPayMoneys(payCategoryList.stream().map(CategoryVo::getBalance).filter(balance -> BigDecimalUtil.biggerThen(balance, BigDecimal.ZERO)).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
                    accountBookVO.setPayCategoryList(payCategoryList);
                    List<CategoryVo> incomeCategoryList = categoryTypeMap.get(Constants.CATEGORY_TYPE_INCOME);
                    accountBookVO.setIncomeMoneys(incomeCategoryList.stream().map(CategoryVo::getBalance).reduce(BigDecimal::add).orElse(BigDecimal.ZERO));
                    accountBookVO.setIncomeCategoryList(incomeCategoryList);
                }
            }
        }
        return accountBookVoList;
    }

    @Override
    public void updateAccountBook(AccountBook accountBook) {
        // 账本下的分类修改后直接调用接口修改了，所以修改账本时不需要修改分类数据，直接修改本身数据即可
        this.check(accountBook, accountBook.getId());
        ColorList.setColor(accountBook, accountBook.getColorIndex());
        accountBook.setWidth(StringUtils.calculateLength(accountBook.getName()));
        accountBook.updateInit();
        this.updateById(accountBook);
        UpdateWrapper<Category> categoryUpdateWrapper = new UpdateWrapper<>();
        categoryUpdateWrapper.in("account_book_id", accountBook.getId());
        categoryUpdateWrapper.set("account_book_name", accountBook.getName());
        categoryService.update(categoryUpdateWrapper);
    }

    @Override
    public AccountBook getAccountBookLimitOne() {
        BaseWrapper<AccountBook> wrapper = new BaseWrapper<>();
        wrapper.init(ThreadLocalUtil.getUserId()).orderByDesc("create_time").last("limit 1");
        return this.getOne(wrapper);
    }
}
